﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;


namespace Common
{
    public static class NativeApi
    {
        #region Windows
        public static List<IntPtr> EnumHwnds()
        {
            var parent = IntPtr.Zero;
            return EnumChildren(parent);
        }

        public static IntPtr GetHwnd(string windowText, string className)
        {
            return (IntPtr)FindWindow(className, windowText);
        }

        public static IntPtr GetHwndFromTitle(string windowText)
        {
            return (IntPtr)FindWindow(null, windowText);
        }

        public static IntPtr GetHwndFromClass(string className)
        {
            return (IntPtr)FindWindow(className, null);
        }

        public static bool ActivateWindow(IntPtr hwnd)
        {
            return SetForegroundWindow(hwnd);
        }

        public static bool KillWindow(IntPtr hwnd)
        {
            ActivateWindow(hwnd);
            return DestroyWindow(hwnd);
        }
        public static bool MinimizeWindow(IntPtr hwnd)
        {
            return CloseWindow(hwnd);
        }

        public static bool IsHandleValid(IntPtr hwnd)
        {
            return IsWindow(hwnd);
        }

        #endregion

        #region Hwnd Attributes
        public static string GetHwndClassName(IntPtr hwnd)
        {
            var result = new StringBuilder(256);
            GetClassName(hwnd, result, result.MaxCapacity);
            return result.ToString();
        }
        public static int GetHwndTitleLength(IntPtr hwnd)
        {
            return GetWindowTextLength(hwnd);
        }
        public static string GetHwndTitle(IntPtr hwnd)
        {
            var length = GetHwndTitleLength(hwnd);
            var result = new StringBuilder(length + 1);
            GetWindowText(hwnd, result, result.Capacity);
            return result.ToString();
        }
        public static bool SetHwndTitle(IntPtr hwnd, string text)
        {
            return SetWindowText(hwnd, text);
        }
        public static bool SetHwndPos(IntPtr hwnd, int x, int y)
        {
            return SetWindowPos(hwnd, IntPtr.Zero, x, y, 0, 0,
                         (uint)(PositionFlags.SWP_NOSIZE | PositionFlags.SWP_NOZORDER));
        }
        public static Point GetHwndPos(IntPtr hwnd)
        {
            var rect = new RECT();
            GetWindowRect(hwnd, out rect);
            var result = new Point(rect.Left, rect.Top);
            return result;
        }

        public static Rectangle GetClientRect(IntPtr hwnd)
        {
            var rect = new RECT();
            GetClientRect(hwnd, out rect);
            var pt = new POINT();
            pt.X = 0;
            pt.Y = 0;
            ClientToScreen(hwnd, ref pt);  
            var result = new Rectangle(pt.X, pt.Y, rect.Right, rect.Bottom);
            return result;
        }
        public static Rectangle GetWindowRect(IntPtr hwnd)
        {
            var rect = new RECT();
            GetWindowRect(hwnd, out rect);
            var result = new Rectangle(rect.Left, rect.Top, rect.Right-rect.Left+1, rect.Bottom-rect.Top+1);
            return result;
        }
        public static bool SetHwndSize(IntPtr hwnd, int w, int h)
        {
            return SetWindowPos(hwnd, IntPtr.Zero, 0, 0, w, h,
                         (uint)(PositionFlags.SWP_NOMOVE | PositionFlags.SWP_NOZORDER));
        }
        public static Size GetHwndSize(IntPtr hwnd)
        {
            var rect = new RECT();
            GetWindowRect(hwnd, out rect);
            var result = new Size(rect.Right - rect.Left+1, rect.Bottom - rect.Top+1);
            return result;
        }
        public static void BringWindowToFront(IntPtr hwnd)
        {
            SetForegroundWindow(hwnd);
        }
        #endregion

        #region Hwnd Functions
        public static List<IntPtr> EnumChildren(IntPtr hwnd)
        {
            var child = IntPtr.Zero;
            var results = new List<IntPtr>();
            do
            {
                child = FindWindowEx(hwnd, child, null, null);
                if (child != IntPtr.Zero) results.Add(child);
            } while (child != IntPtr.Zero);
            return results;
        }
        public static IntPtr GetHwndChild(IntPtr hwnd, string clsName, string ctrlText)
        {
            return FindWindowEx(hwnd, IntPtr.Zero, clsName, ctrlText);
        }
        public static IntPtr GetHwndParent(IntPtr hwnd)
        {
            return GetParent(hwnd);
        }
        public static int SendMessage(IntPtr hwnd, WM msg, uint param1, string param2)
        {
            return (int)SendMessage(hwnd, (uint)msg, param1, param2);
        }
        #endregion


    private struct WINDOWPLACEMENT
    {
        public int length;
        public int flags;
        public int showCmd;
        public System.Drawing.Point ptMinPosition;
        public System.Drawing.Point ptMaxPosition;
        public System.Drawing.Rectangle rcNormalPosition;
    }

    const int SW_NORMAL = 1;
    public static void SetWindowPlacement(IntPtr hwnd,Rectangle rect)
    {
       WINDOWPLACEMENT placement = new WINDOWPLACEMENT();
       placement.length = Marshal.SizeOf(placement);
       placement.showCmd = SW_NORMAL;
       placement.rcNormalPosition = rect;
       SetWindowPlacement(hwnd, ref placement);
    }
        #region lib
        [DllImport("user32.dll")] 
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetWindowPlacement(IntPtr hWnd, ref WINDOWPLACEMENT lpwndpl);

        [DllImport("user32.dll")]
        private static extern int FindWindow(string lpClassName, string lpWindowName);

        // Standard interface
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);

        // Sending messages by string
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, uint wParam, string lParam);

        // Retrieving numeric data
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = false)]
        private static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, uint wParam, uint lParam);

        [DllImport("user32.dll", SetLastError = true)]
        private static extern IntPtr FindWindowEx(IntPtr parentHandle, IntPtr childAfter, string className, string windowTitle);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        private static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);

        [DllImport("USER32.DLL")]
        private static extern bool SetWindowText(IntPtr hWnd, string lpString);

        [DllImport("user32.dll")]
        private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        static extern bool ClientToScreen(IntPtr hWnd, ref POINT lpPoint);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool GetClientRect(IntPtr hWnd, out RECT lpRect);

        [DllImport("user32.dll")]
        private static extern bool CloseWindow(IntPtr hWnd);

        [DllImport("user32.dll")]
        private static extern bool DestroyWindow(IntPtr hWnd);

        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        private static extern IntPtr GetParent(IntPtr hWnd);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool SetForegroundWindow(IntPtr hWnd);

        public delegate bool EnumWindowsCB(IntPtr hwnd, int lparam);
        [DllImport("user32.dll")]
        public static extern int EnumWindows(EnumWindowsCB cb, int lparam);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool IsWindow(IntPtr hWnd);
        #endregion

    }
}
